using Mapster;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using SmartAgricultureService.Core;
using SmartAgricultureService.Models;
using SmartAgricultureService.Models.Enums;
using SmartAgricultureService.Models.Tables;
using SmartAgricultureService.Tables;

namespace SmartAgricultureService.Controllers
{
    [Authorize]
    [ApiController]
    [Route("api/[controller]")]
    public class DevicesController(JwtContext jwt, DatabaseContext database, IHttpContextAccessor httpContextAccessor) : ControllerBase(httpContextAccessor)
    {
        private const string DEFAULT_DEVICE_ID = "6b8f1f42a2e94c629b072f3a7b5e3a4d";
        [AllowAnonymous]
        [HttpPost("login")]
        public async Task<IActionResult> Login([FromBody] LoginInfo loginInfo)
        {
            try
            {
                var deviceEntry = await database.Devices.Include(o => o.Area).AsNoTracking().FirstOrDefaultAsync(x => x.Area.Code == loginInfo.AreaCode && x.Mac == loginInfo.DeviceMac && !x.Delete && x.Active);
                if (deviceEntry != null)
                {
                    var role = deviceEntry.Type == DeviceType.Control ? "admin" : "control";
                    var token = jwt.CreateToken(deviceEntry.Name, deviceEntry.Mac, role);
                    await database.Devices.Where(x => x.Area.Code == loginInfo.AreaCode && x.Mac == loginInfo.DeviceMac).ExecuteUpdateAsync(s => s.SetProperty(e => e.Token, token));
                    return Success(new LoginResult(token, role == "admin"));
                }
                else
                {
                    return Reject($"区域内[{loginInfo.AreaCode}]没有设备MAC[{loginInfo.DeviceMac}]");
                }
            }
            catch (Exception ex)
            {
                return Error(ex);
            }
        }
        [HttpPost("create")]
        public async Task<IActionResult> Create([FromBody] DeviceInfo deviceInfo)
        {
            try
            {
                var hasDevice = await database.Devices.AsNoTracking().FirstOrDefaultAsync(x => x.Mac == deviceInfo.Mac && !x.Delete);
                GetHeader("Authorization", out string token);
                if (hasDevice != null)
                    return Reject($"已存在设备[{deviceInfo.Mac}]");
                else if (deviceInfo.Type == DeviceType.Tablet && !jwt.IsRoleAt(token, "admin"))
                    return Reject($"设备类型[{deviceInfo.Type}]仅可以通过管理员添加");
                else
                {
                    var deviceEntry = new DeviceEntry
                    {
                        Active = true,
                        Delete = false,
                        Mac = deviceInfo.Mac,
                        Type = deviceInfo.Type,
                        Name = deviceInfo.Name,
                        CropId = deviceInfo.CropId,
                        AreaId = deviceInfo.AreaId,
                        Id = Guid.NewGuid().ToString("N")
                    };
                    await database.Devices.AddAsync(deviceEntry);
                    await database.SaveChangesAsync();
                    return Success($"新增设备成功【{deviceEntry.Id}】");
                }
            }
            catch (Exception ex)
            {
                return Error(ex);
            }
        }
        [HttpPost("update")]
        public async Task<IActionResult> Update([FromBody] DeviceInfo deviceInfo)
        {
            try
            {
                var deviceEntry = await database.Devices.FirstOrDefaultAsync(x => x.Id == deviceInfo.Id && !x.Delete);
                GetHeader("Authorization", out string token);
                if (deviceEntry == null)
                    return Reject($"不存在设备名：{deviceInfo.Id}");
                else if (deviceInfo.Type == DeviceType.Tablet && !jwt.IsRoleAt(token, "admin"))
                    return Reject($"设备类型[{deviceInfo.Type}]仅可以通过管理员更新");
                else if (deviceInfo.Id != DEFAULT_DEVICE_ID)
                {
                    deviceEntry.Mac = deviceInfo.Mac;
                    deviceEntry.Name = deviceInfo.Name;
                    deviceEntry.Active = deviceInfo.Active;
                    deviceEntry.AreaId = deviceInfo.AreaId;
                    deviceEntry.CropId = deviceInfo.CropId;
                    await database.SaveChangesAsync();
                    return Success($"更新设备成功【{deviceEntry.Id}】{(deviceInfo.Delete ? "，但拒绝删除设备" : string.Empty)}");
                }
                else
                    return Reject("无效操作");
            }
            catch (Exception ex)
            {
                return Error(ex);
            }
        }
        [HttpDelete("del")]
        public async Task<IActionResult> Delete(string deviceId)
        {
            try
            {
                var deviceEntry = await database.Devices.AsTracking().FirstOrDefaultAsync(x => x.Id == deviceId && !x.Delete);
                GetHeader("Authorization", out string token);
                if (deviceId.Equals(DEFAULT_DEVICE_ID, StringComparison.CurrentCultureIgnoreCase))
                    return Reject("无效操作");
                else if (deviceEntry.Type == DeviceType.Tablet && !jwt.IsRoleAt(token, "admin"))
                    return Reject($"设备类型[{deviceEntry.Type}]仅可以通过管理员删除");
                else if (deviceEntry != null)
                {
                    deviceEntry.Active = false;
                    deviceEntry.Delete = true;
                    await database.SaveChangesAsync();
                    return Success("删除设备成功");
                }
            }
            catch (Exception ex)
            {
                return Error(ex);
            }
            return Reject("删除设备失败");
        }
        [HttpGet("getControl")]
        public async Task<IActionResult> GetControl(string areaCode)
        {
            try
            {
                var deviceInfo = await database.Devices.Include(o => o.Area).AsNoTracking().Where(x => x.Area != null && x.Area.Code == areaCode && x.Type == DeviceType.Tablet && !x.Delete && x.Active).ProjectToType<DeviceInfo>(DeviceInfo.GetAdapterConfig()).FirstOrDefaultAsync();
                return Success(deviceInfo);
            }
            catch (Exception ex)
            {
                return Error(ex);
            }
        }
        [HttpGet("getDevices")]
        public async Task<IActionResult> GetDevices(string areaCode)
        {
            try
            {
                if (!await database.IsMatchArea(areaCode))
                    return Reject("设备不在指定的区域内，无法获取！");
                var deviceInfos = await database.Devices.Include(o => o.Area).AsNoTracking().Where(x => x.Area != null && x.Area.Code == areaCode && x.Type == DeviceType.Iot && !x.Delete && x.Active).ProjectToType<DeviceInfo>(DeviceInfo.GetAdapterConfig()).ToListAsync();
                return Success(deviceInfos);
            }
            catch (Exception ex)
            {
                return Error(ex);
            }
        }
        [HttpGet("getDeviceByMac")]
        public async Task<IActionResult> GetDeviceByMac(string mac)
        {
            try
            {
                var deviceInfo = await database.Devices.Include(o => o.Area).AsNoTracking().Where(x => x.Area != null && x.Mac == mac && x.Type == DeviceType.Iot && !x.Delete && x.Active).ProjectToType<DeviceInfo>(DeviceInfo.GetAdapterConfig()).FirstOrDefaultAsync();
                return Success(deviceInfo);
            }
            catch (Exception ex)
            {
                return Error(ex);
            }
        }
        [HttpGet("getAllDevices")]
        public async Task<IActionResult> GetAllDevices(string areaCode)
        {
            try
            {
                if (!await database.IsMatchArea(areaCode))
                    return Reject("设备不在指定的区域内，无法获取！");
                var deviceInfos = await database.Devices.Include(o => o.Area).AsNoTracking().Where(x => x.Area != null && x.Area.Code == areaCode && !x.Delete && x.Active).ProjectToType<DeviceInfo>(DeviceInfo.GetAdapterConfig()).ToListAsync();
                return Success(deviceInfos);
            }
            catch (Exception ex)
            {
                return Error(ex);
            }
        }
        [HttpGet("getStatus")]
        public IActionResult GetStatus(string deviceId)
        {
            try
            {
                var result = HeartbeatQueue.Instance.GetStatus(deviceId) ? 1 : -1;
                return Success(result);
            }
            catch (Exception ex)
            {
                return Error(ex);
            }
        }
        [HttpGet("getPaging")]
        [Authorize(Roles = "admin")]
        public async Task<IActionResult> GetPaging(int pageIndex, string keywords, int pageSize = 15)
        {
            try
            {
                if (pageIndex == 0) pageIndex = 1;
                var deviceInfos = await database.Devices.AsNoTracking().Where(x => (string.IsNullOrEmpty(keywords) || x.Name.Contains(keywords)) && x.Active && !x.Delete).Paging(pageIndex, pageSize, out var totalPage).ProjectToType<DeviceInfo>(DeviceInfo.GetAdapterConfig()).ToListAsync();
                return Paging(pageIndex, totalPage, deviceInfos, pageSize);
            }
            catch (Exception ex)
            {
                return Error(ex);
            }
        }
    }
}